package com.ry.novel.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ry.novel.model.dto.SysUserInfo;
import com.ry.novel.model.dto.UserInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ry
 * @since 2022-01-22 20:21
 **/
@Component
@Slf4j
public class JwtTokenUtil {
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     *从token中获取jwt的payload
     */
    private Claims getClaimsFromToken(String token){
        Claims claims = null;
        try{
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        }catch (Exception e){
            log.info(e.getMessage());
        }

        return claims;
    }

    /**
     * 根据给定的秒数生成token的过期时间
     */
    private Date generateExpirationDate(){
        /**
         * 返回值为7天后的Date对象
         */
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    /**
     * 从token中获取用户信息
     */
    public UserInfo getUserInfoFromToken(String token){
        if (isTokenExpired(token)){
            return null;
        }

        UserInfo userInfo;
        try {
            Claims claims = getClaimsFromToken(token);
            userInfo = new ObjectMapper().readValue(claims.getSubject(), UserInfo.class);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(),e);

            userInfo =  null;
        }

        return userInfo;
    }

    /**
     * 判断token是否过期
     */
    private Boolean isTokenExpired(String token){
        //token的过期时间
        Date expiredDate = getExpiredDateFromToken(token);
        if (null == expiredDate){
            //已过期
            return true;
        }
        //比当前时间早就是已过期
        return expiredDate.before(new Date());
    }


    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token){
        Claims claims = getClaimsFromToken(token);
        return claims != null ? claims.getExpiration() : null;
    }

    /**
     * 根据用户信息生成token
     */
    public String generateToken(UserInfo userinfo){
        String token;
        try {
            Map<String,Object> claims = new HashMap<>(2);
            claims.put(CLAIM_KEY_USERNAME,new ObjectMapper().writeValueAsString(userinfo));
            claims.put(CLAIM_KEY_CREATED,new Date());
            token = generateToken(claims);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            token =  null;
        }

        return token;
    }

    /**
     * 根据系统用户信息生成token
     */
    public String generateTokenBySysUserInfo(SysUserInfo sysUserInfo){
        String token;
        try {
            Map<String,Object> claims = new HashMap<>(2);
            claims.put(CLAIM_KEY_USERNAME,new ObjectMapper().writeValueAsString(sysUserInfo));
            claims.put(CLAIM_KEY_CREATED,new Date());
            token = generateToken(claims);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            token =  null;
        }

        return token;
    }

    /**
     * 从token中获取系统用户信息
     */
    public SysUserInfo getSysUserInfoFromToken(String token){
        if (isTokenExpired(token)){
            return null;
        }

        SysUserInfo sysUserInfo;
        try {
            Claims claims = getClaimsFromToken(token);
            sysUserInfo = new ObjectMapper().readValue(claims.getSubject(), SysUserInfo.class);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(),e);

            sysUserInfo =  null;
        }

        return sysUserInfo;
    }

    /**
     * 根据claims生成token
     */
    private String generateToken(Map<String,Object> claims){
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512,secret)
                .compact();
    }

    /**
     * 判断token是否可以刷新
     */
    public Boolean canRefresh(String token){
        //过期了的值取反后是false不能刷新
        return !isTokenExpired(token);
    }

    public String refreshToken(String token){
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED,new Date());

        return generateToken(claims);
    }
}
